/**
 * 基础工具类（持续更新）
 * Created by LinWang on 2017/8/8.
 */

import _ from 'lodash';

/*********************** 空判断操作 ***********************/

const nullUtil = {

  /**
   * 判断参数是否为null或者undefined或者""或者" "
   */
  isNullOrEmpty: function(obj) {
    var flag = false;
    if (obj == null || obj == undefined || typeof (obj) == 'undefined' ||
      obj == '') {
      flag = true;
    } else if (typeof (obj) == 'string') {
      //obj = obj.trim();//IE6和7不支持
      var spaceRe = new RegExp('^[ ]+$');
      if (spaceRe.test(obj)) {//为空
        flag = true;
      } else {//不为空
        obj = obj.toUpperCase();
        if (obj == 'NULL' || obj == 'UNDEFINED' || obj == '{}') {
          flag = true;
        }
      }
    }
    else {
      flag = false;
    }
    return flag;
  },

  /**
   * 判断参数是否为null或者undefined
   */
  isNull: function(obj) {
    var flag = false;
    if (obj == null || obj == undefined || typeof (obj) == 'undefined') {
      flag = true;
    }
    return flag;
  },

  /**
   * 判断对象是否为空对象，即{}
   */
  isEmptyObject: function(obj) {
    for (var n in obj) {
      return false;
    }
    return true;
  },

  /**
   * 判断数组是否不为空且有值
   */
  havaArray: function(obj) {
    var flag = false;
    if (obj != null && obj.length > 0) {
      flag = true;
    }
    return flag;
  }
};

/*********************** 数字类操作 ***********************/

const numUtil = {

  /**
   * 判断是否为长度为N的数字串，length等于0或者undefined则不限制长度
   */
  numCheck: function(value, length) {
    var regx;
    if (length == 0 || length == undefined)
      regx = new RegExp('^\\d*$');
    else
      regx = new RegExp('^\\d{' + length + '}$');
    if ((value + '').search(regx) == -1)
      return false;
    else
      return true;
  },

  /**
   * 判断数字串是否为整数
   */
  isInt: function(value) {
    if (~~value == value)
      return true;
    else
      return false;
  },

  /**
   * 判断数字串是否为整数或者小数
   */
  isNum: function(value) {
    if (isNaN(value))
      return false;
    else
      return true;
  },

  /**
   ** 浮点数精确加法
   ** 加法函数，用来得到精确的加法结果
   ** 说明：javascript的加法结果会有误差，在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
   ** 调用：accAdd(arg1,arg2)
   ** 返回值：arg1加上arg2的精确结果
   **/
  aceAdd: function(arg1, arg2) {
    var r1, r2, m, c;
    try {
      r1 = arg1.toString().split('.')[1].length;
    }
    catch (e) {
      r1 = 0;
    }
    try {
      r2 = arg2.toString().split('.')[1].length;
    }
    catch (e) {
      r2 = 0;
    }
    c = Math.abs(r1 - r2);
    m = Math.pow(10, Math.max(r1, r2));
    if (c > 0) {
      var cm = Math.pow(10, c);
      if (r1 > r2) {
        arg1 = Number(arg1.toString().replace('.', ''));
        arg2 = Number(arg2.toString().replace('.', '')) * cm;
      } else {
        arg1 = Number(arg1.toString().replace('.', '')) * cm;
        arg2 = Number(arg2.toString().replace('.', ''));
      }
    } else {
      arg1 = Number(arg1.toString().replace('.', ''));
      arg2 = Number(arg2.toString().replace('.', ''));
    }
    return (arg1 + arg2) / m;
  },

  /**
   ** 浮点数精确减法
   ** 减法函数，用来得到精确的减法结果
   ** 说明：javascript的减法结果会有误差，在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
   ** 调用：accSub(arg1,arg2)
   ** 返回值：arg1加上arg2的精确结果
   **/
  aceSub: function(arg1, arg2) {
    var r1, r2, m, n;
    try {
      r1 = arg1.toString().split('.')[1].length;
    }
    catch (e) {
      r1 = 0;
    }
    try {
      r2 = arg2.toString().split('.')[1].length;
    }
    catch (e) {
      r2 = 0;
    }
    m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
    n = (r1 >= r2) ? r1 : r2;
    return ((arg1 * m - arg2 * m) / m).toFixed(n);
  },

  /**
   ** 浮点数精确乘法
   ** 乘法函数，用来得到精确的乘法结果
   ** 说明：javascript的乘法结果会有误差，在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
   ** 调用：accMul(arg1,arg2)
   ** 返回值：arg1乘以 arg2的精确结果
   **/
  aceMul: function(arg1, arg2) {
    var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
    try {
      m += s1.split('.')[1].length;
    }
    catch (e) {
    }
    try {
      m += s2.split('.')[1].length;
    }
    catch (e) {
    }
    return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) /
      Math.pow(10, m);
  },

  /**
   ** 浮点数精确除法
   ** 除法函数，用来得到精确的除法结果
   ** 说明：javascript的除法结果会有误差，在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
   ** 调用：accDiv(arg1,arg2)
   ** 返回值：arg1除以arg2的精确结果
   **/
  aceDiv: function(arg1, arg2) {
    var t1 = 0, t2 = 0, r1, r2;
    try {
      t1 = arg1.toString().split('.')[1].length;
    }
    catch (e) {
    }
    try {
      t2 = arg2.toString().split('.')[1].length;
    }
    catch (e) {
    }
    r1 = Number(arg1.toString().replace('.', ''));
    r2 = Number(arg2.toString().replace('.', ''));
    return (r1 / r2) * Math.pow(10, t2 - t1);
  },

  /**
   * 金额格式化
   * @param src 待格式化的数字
   * @param pos 取值0-2，代表四舍五入的小数位
   */
  formatFloat: function(src, pos) {
    var num = parseFloat(src).toFixed(pos);
    num = num.toString().replace(/\$|\,/g, '');
    if (isNaN(num)) num = '0';
    sign = (num == (num = Math.abs(num)));
    num = Math.floor(num * 100 + 0.50000000001);
    cents = num % 100;
    num = Math.floor(num / 100).toString();
    if (cents < 10) cents = '0' + cents;
    for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
      num = num.substring(0, num.length - (4 * i + 3)) + ',' +
        num.substring(num.length - (4 * i + 3));
    return (((sign) ? '' : '-') + num + '.' + cents);
  },

  /**
   * 将数值四舍五入(保留2位小数)后格式化成金额形式
   *
   * @param num 数值(Number或者String)
   * @return 金额格式的字符串,如'1,234,567.45'
   * @type String
   */
  formatCurrency: function(num) {
    num = num.toString().replace(/\$|\,/g, '');
    if (isNaN(num))
      num = '0';
    sign = (num == (num = Math.abs(num)));
    num = Math.floor(num * 100 + 0.50000000001);
    cents = num % 100;
    num = Math.floor(num / 100).toString();
    if (cents < 10)
      cents = '0' + cents;
    for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
      num = num.substring(0, num.length - (4 * i + 3)) + ',' +
        num.substring(num.length - (4 * i + 3));
    return (((sign) ? '' : '-') + num + '.' + cents);
  },

  /**
   * 将数值四舍五入(保留1位小数)后格式化成金额形式
   *
   * @param num 数值(Number或者String)
   * @return 金额格式的字符串,如'1,234,567.4'
   * @type String
   */
  formatCurrencyTenThou: function(num) {
    num = num.toString().replace(/\$|\,/g, '');
    if (isNaN(num))
      num = '0';
    sign = (num == (num = Math.abs(num)));
    num = Math.floor(num * 10 + 0.50000000001);
    cents = num % 10;
    num = Math.floor(num / 10).toString();
    for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
      num = num.substring(0, num.length - (4 * i + 3)) + ',' +
        num.substring(num.length - (4 * i + 3));
    return (((sign) ? '' : '-') + num + '.' + cents);
  }
};

/*********************** 字符类操作 ***********************/

const strUtil = {

  /**
   * 去除字符串最后一个字符 （第二个参数缺省代表逗号，常用语拼接JSON数组后去除最后个逗号）
   */
  removeLastChar: function(str, LastChar) {
    var LastCharT = LastChar == undefined ? ',' : LastChar;
    var resultStrAll = str;
    if (resultStrAll.substring(resultStrAll.length - 1, resultStrAll.length) ==
      LastCharT) {
      resultStrAll = resultStrAll.substring(0, resultStrAll.length - 1);
    }
    return resultStrAll;
  },

  /**
   * 验证字符串长度区间（非字符串则都是返回false）
   */
  betweenLength: function(str, _min, _max) {
    return (str.length >= _min && str.length <= _max);
  },

  /**
   * 判断是否有汉字
   * 或使用/[^x00-xff]/g.test(this)
   */
  checkHavaCn: function(str) {
    if (escape(str).indexOf('%u') != -1) {
      alert('含有汉字');
      return true;
    } else {
      alert('全是字符');
      return false;
    }
  },

  /**
   * 正则判断输入字符串是否是由数字字母下划线和横杠组成
   * 横杠是特殊字符，要用反斜扛将它转义：[\-]
   */
  checkStr: function(str) {
    var reg = /^[0-9a-zA-Z_\-]+$/;
    if (!reg.test(str)) {
      return false;
    } else {
      return true;
    }
  },

  /**
   * checkStr加入中文判断
   */
  checkStrCN: function(str) {
    var reg = '^[A-Za-z0-9_\\-\\u4e00-\\u9fa5]+$';
    return new RegExp(reg).test(str);
  },

  /**
   * 是否为合法的手机号码，为了兼容国际写法，目前只判断了是否是+数字
   */
  isMobilePhone: function(value) {
    if (value.search(/^(\+\d{2,3})?\d{11}$/) == -1)
      return false;
    else
      return true;
  },

  /**
   * 是否为合法Email地址
   */
  isEmail: function(value) {
    if (value.search(/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/) == -1)
      return false;
    else
      return true;
  },

  /**
   * 是否为合法的QQ号
   */
  isQQ: function(value) {
    if (value.search(/^[1-9][0-9]{4,}$/) == -1)
      return false;
    else
      return true;
  },

  /**
   * 是否为合法的国内电话号码
   */
  isTelphone: function(value) {
    if (value.search(/^(\d{3}-\d{8}|\d{4}-\d{7}|\d{4}-\d{8})$/) == -1)
      return false;
    else
      return true;
  },

  /**
   * 是否为合法的国内邮政编码
   */
  isZipcode: function(value) {
    if (value.search(/^[1-9]\d{5}$/) == -1)
      return false;
    else
      return true;
  },

  /**
   * 是否为合法IP地址
   */
  isAllIP: function(value, innerIP) {
    var reg_ip = new RegExp('^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$');
    if (!reg_ip.exec(value)) {
      return false;
    }

    var strs = value.split('.');
    if (strs.length != 4) {
      return false;
    }
    for (var i = 0; i < strs.length; i++) {
      if (strs[i].indexOf('0') == 0 && strs[i].length > 1) {
        return false;
      }
      else if (parseInt(strs[i]) > 255 || parseInt(strs[i]) < 0) {
        return false;
      }
    }
    if (innerIP == false) {
      if (value.search(/^192\.168\./) != -1 || value.search(/^172/) != -1 ||
        value.search(/^127\.0/) != -1) {
        return false;
      }
    }
    return true;
  }
};

/*********************** 基础工具，不好归类 ***********************/

const baseUtil = {

  /**
   * ELEMENT UI FORM表单重置为空，传入FORM组件
   * 对整个表单进行重置，将所有字段值重置为空值并移除校验结果
   */
  resetForm: function(form) {
    form.fields.forEach(function(field) {
      field.validateState = '';
      field.validateMessage = '';
      field.validateDisabled = true;
    });
    _.forEach(form.model, function(value, key) {
      form.model[key] = '';
    });
  },

  /**
   * 判断浏览器是否IE浏览器
   */
  checkIE: function() {
    if (!!window.ActiveXObject || 'ActiveXObject' in window) {
      return true;
    } else {
      return false;
    }
  },

  /**
   * 获取一个Java-Map
   */
  newMap: function() {
    return new Map();
  },

  /**
   * 获取一个Java-List
   */
  newList: function() {
    return new List();
  },

  /**
   * iframe访问父元素的方法
   * iframe访问父方法，直接使用parent.方法名()即可
   *
   * @param elementId 元素ID
   * @param JQ_DOM_FLAG 是否返回JQ包装集
   */
  getParentElement: function(elementId, JQ_DOM_FLAG) {
    if (JQ_DOM_FLAG == true) {
      return $('#' + elementId, parent.document);
    } else {
      return window.parent.document.getElementById(elementId);
    }
  },

  /**
   * 父页面访问子元素的方法
   * 父页面访问子方法，直接iframe的name.window.方法名()即可
   *
   * @param iframeId 子元素ID
   * @param elementId 元素ID
   * @param JQ_DOM_FLAG 是否返回JQ包装集
   */
  getIframeElement: function(iframeId, elementId, JQ_DOM_FLAG) {
    if (JQ_DOM_FLAG == true) {
      return $('#' + iframeId).contents().find('#' + elementId);
    } else {
      return document.getElementById('iframeId').
        contentWindow.
        document.
        getElementById(elementId);
    }
  },

  /**
   获取指定的URL参数值
   URL:http://www.blogjava.net/blog?name=bainian
   参数：paramName URL参数
   调用方法:getParam("name")
   返回值:bainian
   */
  getParam: function(paramName) {
    paramValue = '';
    isFound = false;
    if (window.location.search.indexOf('?') == 0 &&
      window.location.search.indexOf('=') > 1) {
      arrSource = unescape(window.location.search).
        substring(1, window.location.search.length).
        split('&');
      i = 0;
      while (i < arrSource.length && !isFound) {
        if (arrSource[i].indexOf('=') > 0) {
          if (arrSource[i].split('=')[0].toLowerCase() ==
            paramName.toLowerCase()) {
            paramValue = arrSource[i].split('=')[1];
            isFound = true;
          }
        }
        i++;
      }
    }
    return paramValue;
  }
};

/**
 * Date对象方法扩展
 */
_.assignIn(Date.prototype, {

  // 对Date的扩展，将 Date 转化为指定格式的String
  // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符，
  // 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
  // 例子：
  // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
  // (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
  // var time1 = new Date().Format("yyyy-MM-dd hh:mm:ss");
  // var time2 = new Date().Format("yyyy-MM-dd");
  // var time3 = new Date("2012-12-12").Format("yyyy-MM-dd hh:mm:ss");
  Format: function(fmt) {
    var o = {
      'M+': this.getMonth() + 1,                 //月份
      'd+': this.getDate(),                    //日
      'h+': this.getHours(),                   //小时
      'm+': this.getMinutes(),                 //分
      's+': this.getSeconds(),                 //秒
      'q+': Math.floor((this.getMonth() + 3) / 3), //季度
      'S': this.getMilliseconds()             //毫秒
    };
    if (/(y+)/.test(fmt))
      fmt = fmt.replace(RegExp.$1,
        (this.getFullYear() + '').substr(4 - RegExp.$1.length));
    for (var k in o)
      if (new RegExp('(' + k + ')').test(fmt))
        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ?
          (o[k]) :
          (('00' + o[k]).substr(('' + o[k]).length)));
    return fmt;
  },



  //日期加减
  //<param name="datepart" type="string">
  //日期加减的部分:
  //Year, yy, yyyy--年
  //quarter, qq, q --季
  //Month, mm, m --    月
  //dayofyear, dy, y--    日
  //Day, dd, d --    日
  //Week, wk, ww --    周
  //Hour, hh --    小时
  //minute, mi, n --    分钟
  //second, ss, s --    秒
  //millisecond, ms --    毫秒
  //</param>
  //<param name="number" type="int">
  //要加减的数量
  //</param>
  //<param name="returnNewObjec" type="bool">
  //若参数为true值，则操作结果由一个新的日期对象返回，原日期对象不变；
  //否则返回的是原日期对象,此时原日期对象的值是操作结果.
  //</param>
  //<returns type="Date">返回一个日期对象
  //调用例子：new Date().add('dayofyear',1,true)
  add: function(datepart, number, returnNewObjec) {

    // var regExp = /^\d+$/;
    // if (regExp.test(number)) {
    //     number = parseInt(number);
    // }
    // else {
    //     number = 0;
    // }
    datepart = datepart.toLowerCase();
    var tDate;
    if (typeof (returnNewObjec) == 'boolean') {
      if (returnNewObjec == true) {
        tDate = new Date(this);
      }
      else {
        tDate = this;
      }
    }
    else {
      tDate = this;
    }

    switch (datepart) {
      case 'year':
      case 'yy':
      case 'yyyy':
        tDate.setFullYear(this.getFullYear() + number);
        break;
      case 'quarter':
      case 'qq':
      case 'q':
        tDate.setMonth(this.getMonth() + (number * 3));
        break;
      case 'month':
      case 'mm':
      case 'm':
        tDate.setMonth(this.getMonth() + number);
        break;
      case 'dayofyear':
      case 'dy':
      case 'y':
      case 'day':
      case 'dd':
      case 'd':
        tDate.setDate(this.getDate() + number);
        break;
      case 'week':
      case 'wk':
      case 'ww':
        tDate.setDate(this.getDate() + (number * 7));
        break;
      case 'hour':
      case 'hh':
        tDate.setHours(this.getHours() + number);
        break;
      case 'minute':
      case 'mi':
      case 'n':
        tDate.setMinutes(this.getMinutes() + number);
        break;
      case 'second':
      case 'ss':
      case 's':
        tDate.setSeconds(this.getSeconds() + number);
        break;
      case 'millisecond':
      case 'ms':
        tDate.setMilliseconds(this.getMilliseconds() + number);
        break;
    }
    return tDate;
  },

  //计算开始日期与当前日期的差,返回差的绝对值。
  //<param name="datepart" type="string">
  //日期加减的部分:
  //Year, yy, yyyy--年 ;
  //quarter, qq, q --季
  //Month, mm, m --    月
  //dayofyear, dy, y--    日
  //Day, dd, d --    日
  //Week, wk, ww --    周
  //Hour, hh --    小时
  //minute, mi, n --    分钟
  //second, ss, s --    秒
  //millisecond, ms --    毫秒
  //</param>
  //<param name="beginDate" type="DateTime">
  //要用于比较的日期
  //</param>
  //<returns type="int">
  //返回日期差的绝对值。
  //</returns>
  //调用例子：new Date().dateDiff('dayofyear',new Date('2014-9-26'))
  dateDiff: function(datepart, beginDate) {
    datepart = datepart.toLowerCase();
    var yearDiff = Math.abs(this.getFullYear() - beginDate.getFullYear());
    switch (datepart) {
      case 'year':
      case 'yy':
      case 'yyyy':
        return yearDiff;
      case 'quarter':
      case 'qq':
      case 'q':
        var qDiff = 0;
        switch (yearDiff) {
          case 0:
            qDiff = Math.abs(this.getSeason() - beginDate.getSeason());
            break;
          case 1:
            qDiff = (this.getSeason() -
              new Date(this.getFullYear(), 0, 1).getSeason()) +
              (new Date(beginDate.getFullYear(), 11, 31).getSeason() -
                beginDate.getSeason()) + 1;
            break;
          default:
            qDiff = (this.getSeason() -
              new Date(this.getFullYear(), 0, 1).getSeason()) +
              (new Date(beginDate.getFullYear(), 11, 31).getSeason() -
                beginDate.getSeason()) + 1 + (yearDiff - 1) * 4;
            break;
        }
        return qDiff;
      case 'month':
      case 'mm':
      case 'm':
        var monthDiff = 0;
        switch (yearDiff) {
          case 0:
            monthDiff = Math.abs(this.getMonth() - beginDate.getMonth());
            break;
          case 1:
            monthDiff = (this.getMonth() -
              new Date(this.getFullYear(), 0, 1).getMonth()) +
              (new Date(beginDate.getFullYear(), 11, 31).getMonth() -
                beginDate.getMonth()) + 1;
            break;
          default:
            monthDiff = (this.getMonth() -
              new Date(this.getFullYear(), 0, 1).getMonth()) +
              (new Date(beginDate.getFullYear(), 11, 31).getMonth() -
                beginDate.getMonth()) + 1 + (yearDiff - 1) * 12;
            break;
        }
        return monthDiff;
      case 'dayofyear':
      case 'dy':
      case 'y':
      case 'day':
      case 'dd':
      case 'd':
        return Math.abs((this.setHours(0, 0, 0, 0) -
          beginDate.setHours(0, 0, 0, 0)) / 1000 / 60 / 60 / 24);
      case 'week':
      case 'wk':
      case 'ww':
        var weekDiff = 0;
        switch (yearDiff) {
          case 0:
            weekDiff = Math.abs(this.getWeek() - beginDate.getWeek());
            break;
          case 1:
            weekDiff = (this.getWeek() -
              new Date(this.getFullYear(), 0, 1).getWeek()) +
              (new Date(beginDate.getFullYear(), 11, 31).getWeek() -
                beginDate.getWeek()) + 1;
            break;
          default:

            weekDiff = (this.getWeek() -
              new Date(this.getFullYear(), 0, 1).getWeek()) +
              (new Date(beginDate.getFullYear(), 11, 31).getWeek() -
                beginDate.getWeek()) + 1;
            var thisYear = this.getFullYear();
            for (var i = 1; i < yearDiff; i++) {
              weekDiff += new Date(thisYear - i, 0, 1).getWeeksOfYear();
            }
            break;
        }
        return weekDiff;
      case 'hour':
      case 'hh':
        return Math.abs((this - beginDate) / 1000 / 60 / 60);
      case 'minute':
      case 'mi':
      case 'n':
        return Math.abs((this - beginDate) / 1000 / 60);
      case 'second':
      case 'ss':
      case 's':
        return Math.abs((this - beginDate) / 1000);
      case 'millisecond':
      case 'ms':
        return Math.abs(this - beginDate);
    }
  }
});

baseUtil.toLongStringFormat = function(time){
  new Date(time).Format('yyyy-MM-dd hh:mm:ss');
}

baseUtil.toShortStringFormat = function(time){
  new Date(time).Format('yyyy-MM-dd');
}

const exportsObj = _.assignIn({}, nullUtil, baseUtil, strUtil, numUtil);

export default exportsObj;
